﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using Library.Collections.Distributed;
using Library.Distributed;
using INDEX = System.UInt64;

namespace Library.Linq.Distributed
{
    public static class DistributedEnumerable
    {
        public static IDistributedEnumerable AsDistributed(this IEnumerable source)
        {
            IDistributedEnumerable distributed = source as IDistributedEnumerable;
            if (distributed != null) return distributed;
            return Context.Current.Compose(source);
        }
        public static IDistributedEnumerable<TSource> AsDistributed<TSource>(this IEnumerable<TSource> source)
        {
            IDistributedEnumerable<TSource> distributed = source as IDistributedEnumerable<TSource>;
            if (distributed != null) return distributed;
            IDistributedEnumerable distributed2 = source as IDistributedEnumerable;
            if (distributed2 != null) return distributed2.Cast<TSource>();
            return Context.Current.Compose(source);
        }

        public static TSource Aggregate<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, TSource, TSource>> aggregation)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Queryable.Aggregate<TSource>(queryable, aggregation);

            throw new NotImplementedException();
        }
        public static bool All<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, bool>> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Queryable.All<TSource>(queryable, predicate);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().All(predicate), (ctx, x) => ctx.All(x));
        }
        public static bool Any<TSource>(this IDistributedEnumerable<TSource> source)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Queryable.Any<TSource>(queryable);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.Any(), (ctx, x) => ctx.Any(x));
        }
        public static bool Any<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, bool>> predicate)
        {
            System.Linq.IQueryable<TSource> queryable = source as System.Linq.IQueryable<TSource>;
            if (queryable != null)
                return Queryable.Any<TSource>(queryable, predicate);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Any(predicate), (ctx, x) => ctx.Any(x));
        }
        public static IDistributedEnumerable<TSource> AsEnumerable<TSource>(this IDistributedEnumerable source)
        {
            IDistributedEnumerable<TSource> enumerable = source as IDistributedEnumerable<TSource>;
            if (enumerable != null)
            {
                return enumerable;
            }
            else
            {
                return Platform.Current.Invoke(source, x => x.Cast<TSource>(), (ctx, x) => ctx.Compose(x));
            }
        }
        public static IDistributedQueryable<TSource> AsQueryable<TSource>(this IDistributedEnumerable<TSource> source)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
            {
                return queryable;
            }
            else
            {
                return Platform.Current.Invoke((IDistributed<IEnumerable<TSource>>)source, x => x.AsQueryable(), (ctx, x) => ctx.Compose(x));
            }
        }
        public static decimal Average(this IDistributedEnumerable<decimal> source)
        {
            throw new NotImplementedException();
        }
        public static float Average(this IDistributedEnumerable<float> distributed)
        {
            throw new NotImplementedException();
        }
        public static double Average(this IDistributedEnumerable<double> distributed)
        {
            throw new NotImplementedException();
        }
        public static sbyte Average(this IDistributedEnumerable<sbyte> distributed)
        {
            throw new NotImplementedException();
        }
        public static short Average(this IDistributedEnumerable<short> distributed)
        {
            throw new NotImplementedException();
        }
        public static int Average(this IDistributedEnumerable<int> distributed)
        {
            throw new NotImplementedException();
        }
        public static long Average(this IDistributedEnumerable<long> distributed)
        {
            throw new NotImplementedException();
        }
        public static byte Average(this IDistributedEnumerable<byte> distributed)
        {
            throw new NotImplementedException();
        }
        public static ushort Average(this IDistributedEnumerable<ushort> distributed)
        {
            throw new NotImplementedException();
        }
        public static uint Average(this IDistributedEnumerable<uint> distributed)
        {
            throw new NotImplementedException();
        }
        public static ulong Average(this IDistributedEnumerable<ulong> distributed)
        {
            throw new NotImplementedException();
        }
        public static IDistributedEnumerable<TResult> Cast<TResult>(this IDistributedEnumerable source)
        {
            IDistributedEnumerable<TResult> enumerable = source as IDistributedEnumerable<TResult>;
            if (enumerable != null)
                return enumerable;

            IDistributedQueryable queryable = source as IDistributedQueryable;
            if (queryable != null)
                return DistributedQueryable.Cast<TResult>(queryable);

            return Platform.Current.Invoke(source, x => x.Cast<TResult>(), (ctx, x) => ctx.Compose(x));
        }
        public static IDistributedEnumerable<TSource> Concat<TSource>(this IDistributedEnumerable<TSource> first, IDistributedEnumerable<TSource> second)
        {
            IDistributedQueryable<TSource> queryable = first as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.Concat<TSource>(queryable, second);

            throw new NotImplementedException();
        }
        public static bool Contains<TSource>(this IDistributedEnumerable<TSource> source, TSource value)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.Contains<TSource>(queryable, value);

            Library.Collections.Generic.IContainer<TSource> container = source as Library.Collections.Generic.IContainer<TSource>;
            if (container != null)
                return container.Contains(value);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.Contains(value), (ctx, x) => ctx.Any(x));
        }
        public static INDEX Count<TSource>(this IDistributedEnumerable<TSource> source)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.Count<TSource>(queryable);

            Library.Collections.ICountable countable = source as Library.Collections.ICountable;
            if (countable != null)
                return countable.Count;

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.Count(), (ctx, x) => ctx.Sum(x));
        }
        public static INDEX Count<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, bool>> predicate)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.Count<TSource>(queryable, predicate);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Count(predicate), (ctx, x) => ctx.Sum(x));
        }
        public static IDistributedEnumerable<TSource> Distinct<TSource>(this IDistributedEnumerable<TSource> source)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.Distinct<TSource>(queryable);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.Distinct(), (ctx, x) => ctx.ComposeDistinct(x));
        }
        public static TSource ElementAt<TSource>(this IDistributedEnumerable<TSource> source, INDEX index)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.ElementAt<TSource>(queryable, index);

            Library.Collections.Generic.IVectorReadOnly<TSource> vector = source as Library.Collections.Generic.IVectorReadOnly<TSource>;
            if (vector != null)
                return vector[index];

            throw new NotImplementedException();
        }
        public static TSource ElementAtOrDefault<TSource>(this IDistributedEnumerable<TSource> source, INDEX index)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.ElementAtOrDefault<TSource>(queryable, index);

            Library.Collections.Generic.IVectorReadOnly<TSource> vector = source as Library.Collections.Generic.IVectorReadOnly<TSource>;
            if (vector != null)
            {
                try
                {
                    return vector[index];
                }
                catch
                {
                    return default(TSource);
                }
            }

            throw new NotImplementedException();
        }
        public static IDistributedEnumerable<TResult> Empty<TResult>()
        {
            throw new NotImplementedException();
        }
        public static IDistributedEnumerable<TSource> Except<TSource>(this IDistributedEnumerable<TSource> first, IEnumerable<TSource> second)
        {
            IDistributedQueryable<TSource> queryable = first as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.Except<TSource>(queryable, second);

            throw new NotImplementedException();
        }
        public static TSource First<TSource>(this IDistributedEnumerable<TSource> source)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.First<TSource>(queryable);

            throw new NotImplementedException();
        }
        public static TSource First<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, bool>> predicate)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.First<TSource>(queryable, predicate);

            throw new NotImplementedException();
        }
        public static TSource FirstOrDefault<TSource>(this IDistributedEnumerable<TSource> source)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.FirstOrDefault<TSource>(queryable);

            throw new NotImplementedException();
        }
        public static TSource FirstOrDefault<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, bool>> predicate)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.FirstOrDefault<TSource>(queryable, predicate);

            throw new NotImplementedException();
        }
        public static IDistributedEnumerable<System.Linq.IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.GroupBy<TSource, TKey>(queryable, keySelector);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().GroupBy(keySelector), (ctx, x)=>ctx.Compose(x, keySelector));
        }
        public static IDistributedEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, TKey>> keySelector, Expression<Func<TKey, IEnumerable<TSource>, TResult>> resultSelector)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.GroupBy<TSource, TKey, TResult>(queryable, keySelector, resultSelector);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().GroupBy(keySelector), (ctx, x)=>ctx.Compose(x, keySelector, resultSelector));
        }
        public static IDistributedEnumerable<System.Linq.IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, TKey>> keySelector, Expression<Func<TSource, TElement>> elementSelector)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.GroupBy<TSource, TKey, TElement>(queryable, keySelector, elementSelector);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().GroupBy(keySelector), (ctx, x) => ctx.Compose(x, keySelector, elementSelector));
        }
        public static IDistributedEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, TKey>> keySelector, Expression<Func<TSource, TElement>> elementSelector, Expression<Func<TKey, IEnumerable<TElement>, TResult>> resultSelector)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.GroupBy<TSource, TKey, TElement, TResult>(queryable, keySelector, elementSelector, resultSelector);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().GroupBy(keySelector), (ctx, x) => ctx.Compose(x, keySelector, elementSelector, resultSelector));
        }
        public static IDistributedEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IDistributedEnumerable<TOuter> outer, IEnumerable<TInner> inner, Expression<Func<TOuter, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<TOuter, IEnumerable<TInner>, TResult>> resultSelector)
        {
            IDistributedQueryable<TOuter> queryable = outer as IDistributedQueryable<TOuter>;
            if (queryable != null)
                return DistributedQueryable.GroupJoin<TOuter, TInner, TKey, TResult>(queryable, inner, outerKeySelector, innerKeySelector, resultSelector);

            return Platform.Current.Invoke(outer, (IEnumerable<TOuter> x) => x.AsQueryable().GroupJoin(inner, outerKeySelector, innerKeySelector, resultSelector), (ctx, x) => ctx.Compose(x));
        }
        public static IDistributedEnumerable<TSource> Intersect<TSource>(this IDistributedEnumerable<TSource> first, IEnumerable<TSource> second)
        {
            IDistributedQueryable<TSource> queryable = first as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.Intersect<TSource>(queryable, second);

            throw new NotImplementedException();
        }
        public static IDistributedEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IDistributedEnumerable<TOuter> outer, IEnumerable<TInner> inner, Expression<Func<TOuter, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<TOuter, TInner, TResult>> resultSelector)
        {
            IDistributedQueryable<TOuter> queryable = outer as IDistributedQueryable<TOuter>;
            if (queryable != null)
                return DistributedQueryable.Join<TOuter, TInner, TKey, TResult>(queryable, inner, outerKeySelector, innerKeySelector, resultSelector);

            return Platform.Current.Invoke(outer, (IEnumerable<TOuter> x) => x.AsQueryable().Join(inner, outerKeySelector, innerKeySelector, resultSelector), (ctx, x) => ctx.Compose(x));
        }
        public static TSource Last<TSource>(this IDistributedEnumerable<TSource> source)
        {
            throw new NotImplementedException();
        }
        public static TSource Last<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, bool>> predicate)
        {
            throw new NotImplementedException();
        }
        public static TSource LastOrDefault<TSource>(this IDistributedEnumerable<TSource> source)
        {
            throw new NotImplementedException();
        }
        public static TSource LastOrDefault<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, bool>> predicate)
        {
            throw new NotImplementedException();
        }
        public static ulong LongCount<TSource>(this IDistributedEnumerable<TSource> source)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.LongCount<TSource>(queryable);

            Library.Collections.ICountable countable = source as Library.Collections.ICountable;
            if (countable != null)
                return countable.Count;

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => Library.Linq.Enumerable.LongCount(x), (ctx, x) => ctx.Sum(x));
        }
        public static ulong LongCount<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, bool>> predicate)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().LongCount(predicate), (ctx, x) => ctx.Sum(x));
        }
        public static decimal Max(this IDistributedEnumerable<decimal> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<decimal> x) => x.Max(), (ctx, x) => ctx.Max(x));
        }
        public static float Max(this IDistributedEnumerable<float> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<float> x) => x.Max(), (ctx, x) => ctx.Max(x));
        }
        public static double Max(this IDistributedEnumerable<double> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<double> x) => x.Max(), (ctx, x) => ctx.Max(x));
        }
        public static sbyte Max(this IDistributedEnumerable<sbyte> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<sbyte> x) => x.Max(), (ctx, x) => ctx.Max(x));
        }
        public static short Max(this IDistributedEnumerable<short> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<short> x) => x.Max(), (ctx, x) => ctx.Max(x));
        }
        public static int Max(this IDistributedEnumerable<int> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<int> x) => x.Max(), (ctx, x) => ctx.Max(x));
        }
        public static long Max(this IDistributedEnumerable<long> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<long> x) => x.Max(), (ctx, x) => ctx.Max(x));
        }
        public static byte Max(this IDistributedEnumerable<byte> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<byte> x) => x.Max(), (ctx, x) => ctx.Max(x));
        }
        public static ushort Max(this IDistributedEnumerable<ushort> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<ushort> x) => x.Max(), (ctx, x) => ctx.Max(x));
        }
        public static uint Max(this IDistributedEnumerable<uint> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<uint> x) => x.Max(), (ctx, x) => ctx.Max(x));
        }
        public static ulong Max(this IDistributedEnumerable<ulong> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<ulong> x) => x.Max(), (ctx, x) => ctx.Max(x));
        }
        public static TSource Max<TSource>(this IDistributedEnumerable<TSource> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.Max(), (ctx, x) => ctx.Max(x));
        }
        public static decimal Max<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, decimal>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Max(function), (ctx, x) => ctx.Max(x));
        }
        public static float Max<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, float>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Max(function), (ctx, x) => ctx.Max(x));
        }
        public static double Max<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, double>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Max(function), (ctx, x) => ctx.Max(x));
        }
        public static sbyte Max<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, sbyte>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Max(function), (ctx, x) => ctx.Max(x));
        }
        public static short Max<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, short>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Max(function), (ctx, x) => ctx.Max(x));
        }
        public static int Max<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, int>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Max(function), (ctx, x) => ctx.Max(x));
        }
        public static long Max<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, long>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Max(function), (ctx, x) => ctx.Max(x));
        }
        public static byte Max<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, byte>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Max(function), (ctx, x) => ctx.Max(x));
        }
        public static ushort Max<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, ushort>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Max(function), (ctx, x) => ctx.Max(x));
        }
        public static uint Max<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, uint>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Max(function), (ctx, x) => ctx.Max(x));
        }
        public static ulong Max<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, ulong>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Max(function), (ctx, x) => ctx.Max(x));
        }
        public static TResult Max<TSource, TResult>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, TResult>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Max(function), (ctx, x) => ctx.Max(x));
        }
        public static decimal Min(this IDistributedEnumerable<decimal> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<decimal> x) => x.Min(), (ctx, x) => ctx.Min(x));
        }
        public static float Min(this IDistributedEnumerable<float> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<float> x) => x.Min(), (ctx, x) => ctx.Min(x));
        }
        public static double Min(this IDistributedEnumerable<double> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<double> x) => x.Min(), (ctx, x) => ctx.Min(x));
        }
        public static sbyte Min(this IDistributedEnumerable<sbyte> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<sbyte> x) => x.Min(), (ctx, x) => ctx.Min(x));
        }
        public static short Min(this IDistributedEnumerable<short> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<short> x) => x.Min(), (ctx, x) => ctx.Min(x));
        }
        public static int Min(this IDistributedEnumerable<int> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<int> x) => x.Min(), (ctx, x) => ctx.Min(x));
        }
        public static long Min(this IDistributedEnumerable<long> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<long> x) => x.Min(), (ctx, x) => ctx.Min(x));
        }
        public static byte Min(this IDistributedEnumerable<byte> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<byte> x) => x.Min(), (ctx, x) => ctx.Min(x));
        }
        public static ushort Min(this IDistributedEnumerable<ushort> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<ushort> x) => x.Min(), (ctx, x) => ctx.Min(x));
        }
        public static uint Min(this IDistributedEnumerable<uint> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<uint> x) => x.Min(), (ctx, x) => ctx.Min(x));
        }
        public static ulong Min(this IDistributedEnumerable<ulong> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<ulong> x) => x.Min(), (ctx, x) => ctx.Min(x));
        }
        public static TSource Min<TSource>(this IDistributedEnumerable<TSource> source)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.Min(), (ctx, x) => ctx.Min(x));
        }
        public static decimal Min<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, decimal>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Min(function), (ctx, x) => ctx.Min(x));
        }
        public static float Min<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, float>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Min(function), (ctx, x) => ctx.Min(x));
        }
        public static double Min<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, double>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Min(function), (ctx, x) => ctx.Min(x));
        }
        public static sbyte Min<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, sbyte>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Min(function), (ctx, x) => ctx.Min(x));
        }
        public static short Min<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, short>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Min(function), (ctx, x) => ctx.Min(x));
        }
        public static int Min<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, int>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Min(function), (ctx, x) => ctx.Min(x));
        }
        public static long Min<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, long>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Min(function), (ctx, x) => ctx.Min(x));
        }
        public static byte Min<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, byte>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Min(function), (ctx, x) => ctx.Min(x));
        }
        public static ushort Min<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, ushort>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Min(function), (ctx, x) => ctx.Min(x));
        }
        public static uint Min<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, uint>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Min(function), (ctx, x) => ctx.Min(x));
        }
        public static ulong Min<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, ulong>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Min(function), (ctx, x) => ctx.Min(x));
        }
        public static TResult Min<TSource, TResult>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, TResult>> function)
        {
            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Min(function), (ctx, x) => ctx.Min(x));
        }
        public static IDistributedEnumerable<TResult> OfType<TResult>(this IDistributedEnumerable source)
        {
            IDistributedQueryable queryable = source as IDistributedQueryable;
            if (queryable != null)
                return DistributedQueryable.OfType<TResult>(queryable);

            return Platform.Current.Invoke(source, x => x.OfType<TResult>(), (ctx, x) => ctx.Compose(x));
        }
        public static IDistributedOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.OrderBy<TSource, TKey>(queryable, keySelector);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.OrderBy(keySelector.Compile()), (ctx, x) => ctx.Compose(x, keySelector));
        }
        public static IDistributedOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.OrderByDescending<TSource, TKey>(queryable, keySelector);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.OrderByDescending(keySelector.Compile()), (ctx, x) => ctx.Compose(x, keySelector, true));
        }
        public static IDistributedEnumerable<TSource> Reverse<TSource>(this IDistributedEnumerable<TSource> source)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.Reverse<TSource>(queryable);

            throw new NotImplementedException();
        }
        public static IDistributedEnumerable<TResult> Select<TSource, TResult>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, TResult>> selector)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.Select<TSource, TResult>(queryable, selector);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().Select(selector), (ctx, x) => ctx.Compose(x));
        }
        public static IDistributedEnumerable<TResult> SelectMany<TSource, TResult>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, IEnumerable<TResult>>> selector)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.SelectMany<TSource, TResult>(queryable, selector);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().SelectMany(selector), (ctx, x) => ctx.Compose(x));
        }
        public static IDistributedEnumerable<TResult> SelectMany<TSource, TResult>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, INDEX, IEnumerable<TResult>>> selector)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.SelectMany<TSource, TResult>(queryable, selector);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().SelectMany(selector), (ctx, x) => ctx.Compose(x));
        }
        public static IDistributedEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, IEnumerable<TCollection>>> collectionSelector, Expression<Func<TSource, TCollection, TResult>> resultSelector)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.SelectMany<TSource, TCollection, TResult>(queryable, collectionSelector, resultSelector);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().SelectMany(collectionSelector, resultSelector), (ctx, x) => ctx.Compose(x));
        }
        public static IDistributedEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, INDEX, IEnumerable<TCollection>>> collectionSelector, Expression<Func<TSource, TCollection, TResult>> resultSelector)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.SelectMany<TSource, TCollection, TResult>(queryable, collectionSelector, resultSelector);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x.AsQueryable().SelectMany(collectionSelector, resultSelector), (ctx, x) => ctx.Compose(x));
        }
        public static bool SequenceEqual<TSource>(this IDistributedEnumerable<TSource> first, IEnumerable<TSource> second)
        {
            throw new NotImplementedException();
        }
        public static TSource Single<TSource>(this IDistributedEnumerable<TSource> source)
        {
            throw new NotImplementedException();
        }
        public static TSource Single<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, bool>> predicate)
        {
            throw new NotImplementedException();
        }
        public static TSource SingleOrDefault<TSource>(this IDistributedEnumerable<TSource> source)
        {
            throw new NotImplementedException();
        }
        public static TSource SingleOrDefault<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, bool>> predicate)
        {
            throw new NotImplementedException();
        }
        public static IDistributedEnumerable<TSource> Skip<TSource>(this IDistributedEnumerable<TSource> source, INDEX count)
        {
            throw new NotImplementedException();
        }
        public static IDistributedEnumerable<TSource> SkipWhile<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, bool>> predicate)
        {
            throw new NotImplementedException();
        }
        public static IDistributedEnumerable<TSource> SkipWhile<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, INDEX, bool>> predicate)
        {
            throw new NotImplementedException();
        }
        public static decimal Sum(this IDistributedEnumerable<decimal> distributed)
        {
            return Platform.Current.Invoke(distributed, (IEnumerable<decimal> x) => x.Sum(), (ctx, x) => ctx.Sum(x));
        }
        public static float Sum(this IDistributedEnumerable<float> distributed)
        {
            return Platform.Current.Invoke(distributed, (IEnumerable<float> x) => x.Sum(), (ctx, x) => ctx.Sum(x));
        }
        public static double Sum(this IDistributedEnumerable<double> distributed)
        {
            return Platform.Current.Invoke(distributed, (IEnumerable<double> x) => x.Sum(), (ctx, x) => ctx.Sum(x));
        }
        public static int Sum(this IDistributedEnumerable<int> distributed)
        {
            return Platform.Current.Invoke(distributed, (IEnumerable<int> x) => x.Sum(), (ctx, x) => ctx.Sum(x));
        }
        public static long Sum(this IDistributedEnumerable<long> distributed)
        {
            return Platform.Current.Invoke(distributed, (IEnumerable<long> x) => x.Sum(), (ctx, x) => ctx.Sum(x));
        }
        public static IDistributedEnumerable<TSource> Take<TSource>(this IDistributedEnumerable<TSource> source, uint count)
        {
            throw new NotImplementedException();
        }
        public static IDistributedEnumerable<TSource> TakeWhile<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, bool>> predicate)
        {
            throw new NotImplementedException();
        }
        public static IDistributedEnumerable<TSource> TakeWhile<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, INDEX, bool>> predicate)
        {
            throw new NotImplementedException();
        }
        public static IDistributedOrderedEnumerable<TSource> ThenBy<TSource, TKey>(this IDistributedOrderedEnumerable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
        {
            IDistributedOrderedQueryable<TSource> queryable = source as IDistributedOrderedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.ThenBy<TSource, TKey>(queryable, keySelector);

            throw new NotImplementedException();
        }
        public static IDistributedOrderedEnumerable<TSource> ThenByDescending<TSource, TKey>(this IDistributedOrderedEnumerable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
        {
            IDistributedOrderedQueryable<TSource> queryable = source as IDistributedOrderedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.ThenByDescending<TSource, TKey>(queryable, keySelector);

            throw new NotImplementedException();
        }
        public static IDistributedEnumerable<TSource> Union<TSource>(this IDistributedEnumerable<TSource> first, IEnumerable<TSource> second)
        {
            IDistributedQueryable<TSource> queryable = first as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.Union<TSource>(queryable, second);

            throw new NotImplementedException();
        }
        public static IDistributedEnumerable<TSource> Where<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, bool>> predicate)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.Where<TSource>(queryable, predicate);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x, (ctx, x) => ctx.Compose(x, predicate));
        }
        public static IDistributedEnumerable<TSource> Where<TSource>(this IDistributedEnumerable<TSource> source, Expression<Func<TSource, INDEX, bool>> predicate)
        {
            IDistributedQueryable<TSource> queryable = source as IDistributedQueryable<TSource>;
            if (queryable != null)
                return DistributedQueryable.Where<TSource>(queryable, predicate);

            return Platform.Current.Invoke(source, (IEnumerable<TSource> x) => x, (ctx, x) => ctx.Compose(x, predicate));
        }
        public static IDistributedEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Expression<Func<TFirst, TSecond, TResult>> resultSelector)
        {
            throw new NotImplementedException();
        }
    }
}

